package org.lc.scoretj.service.impl;

import org.lc.scoretj.model.*;
import org.lc.scoretj.repository.*;
import org.lc.scoretj.service.ScoreStatisticsService;

import org.lc.scoretj.util.GradeCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 成绩统计服务实现类
 */
@Service
@Transactional
public class ScoreStatisticsServiceImpl implements ScoreStatisticsService {

    private static final Logger logger = LoggerFactory.getLogger(ScoreStatisticsServiceImpl.class);

    @Autowired
    private ScoreRepository scoreRepository;

    @Autowired
    private TrainingLevelStatisticsRepository trainingLevelStatisticsRepository;

    @Autowired
    private TrainingLevelMajorStatisticsRepository trainingLevelMajorStatisticsRepository;

    @Autowired
    private TrainingLevelMajorTeamStatisticsRepository trainingLevelMajorTeamStatisticsRepository;

    @Autowired
    private TrainingLevelMajorTeamCourseStatisticsRepository trainingLevelMajorTeamCourseStatisticsRepository;

    @Autowired
    private CourseStatisticsRepository courseStatisticsRepository;

    @Autowired
    private CourseGapAnalysisRepository courseGapAnalysisRepository;

    


    @Override
    public void executeAllStatistics(String xueQe) {
    logger.info("开始执行所有统计分析, xueQe={}", xueQe);
    clearAllStatistics();
    logger.info("完成清空统计表");

    logger.info("开始按培养层次统计");
    statisticsByTrainingLevel(xueQe);
    logger.info("按培养层次统计完成");

    logger.info("开始按培养层次-专业统计");
    statisticsByTrainingLevelAndMajor(xueQe);
    logger.info("按培养层次-专业统计完成");

    logger.info("开始按培养层次-专业-队别统计");
    statisticsByTrainingLevelAndMajorAndTeam(xueQe);
    logger.info("按培养层次-专业-队别统计完成");

    logger.info("开始按培养层次-专业-队别-课程统计");
    statisticsByTrainingLevelAndMajorAndTeamAndCourse(xueQe);
    logger.info("按培养层次-专业-队别-课程统计完成");

    logger.info("开始按课程统计");
    statisticsByCourse(xueQe);
    logger.info("按课程统计完成");

    logger.info("开始课程间差距分析");
    analyzeCourseGap(xueQe);
    logger.info("课程间差距分析完成");

    // 课程相关性分析已移除
    }

    /**
     * 计算两个队别的聚合指标差距并设置到 CourseGapAnalysis 中（使用反射，根据 prefix 构造 setter 名称）
     */
    private void computeTeamGap(List<Score> scoresA, List<Score> scoresB, CourseGapAnalysis analysis,
                               GradeCalculator.ScoreGetter scoreGetter, String prefix) {
        // 计算平均分差距
        Float avgA = GradeCalculator.calculateAverage(scoresA, scoreGetter);
        Float avgB = GradeCalculator.calculateAverage(scoresB, scoreGetter);
        Float avgGap = null;
        if (avgA != null && avgB != null) avgGap = Math.abs(avgA - avgB);

        // 计算优秀/不及格率（以有效记录为分母），并取绝对差值，保留 3 位小数
        Map<String, Integer> countsA = GradeCalculator.countGradeLevels(scoresA, scoreGetter);
        Map<String, Integer> countsB = GradeCalculator.countGradeLevels(scoresB, scoreGetter);
        int validA = (scoresA == null) ? 0 : (int) scoresA.stream().filter(s -> scoreGetter.getScore(s) != null).count();
        int validB = (scoresB == null) ? 0 : (int) scoresB.stream().filter(s -> scoreGetter.getScore(s) != null).count();

        Float excellentRateA = null, excellentRateB = null, excellentRateGap = null;
        Float failRateA = null, failRateB = null, failRateGap = null;

        try {
            if (validA > 0) {
                excellentRateA = new java.math.BigDecimal(countsA.getOrDefault("excellent", 0))
                        .divide(new java.math.BigDecimal(validA), 5, java.math.RoundingMode.HALF_UP)
                        .setScale(3, java.math.RoundingMode.HALF_UP).floatValue();
                failRateA = new java.math.BigDecimal(countsA.getOrDefault("fail", 0))
                        .divide(new java.math.BigDecimal(validA), 5, java.math.RoundingMode.HALF_UP)
                        .setScale(3, java.math.RoundingMode.HALF_UP).floatValue();
            }
            if (validB > 0) {
                excellentRateB = new java.math.BigDecimal(countsB.getOrDefault("excellent", 0))
                        .divide(new java.math.BigDecimal(validB), 5, java.math.RoundingMode.HALF_UP)
                        .setScale(3, java.math.RoundingMode.HALF_UP).floatValue();
                failRateB = new java.math.BigDecimal(countsB.getOrDefault("fail", 0))
                        .divide(new java.math.BigDecimal(validB), 5, java.math.RoundingMode.HALF_UP)
                        .setScale(3, java.math.RoundingMode.HALF_UP).floatValue();
            }

            if (excellentRateA != null && excellentRateB != null) {
                excellentRateGap = Math.abs(excellentRateA - excellentRateB);
            }
            if (failRateA != null && failRateB != null) {
                failRateGap = Math.abs(failRateA - failRateB);
            }

            String capPrefix = prefix.substring(0, 1).toUpperCase() + prefix.substring(1);
            logger.debug("computeTeamGap prefix={} capPrefix={} avgGap={} excellentRateGap={} failRateGap={}", prefix, capPrefix, avgGap, excellentRateGap, failRateGap);
            // set average gap
            analysis.getClass().getMethod("set" + capPrefix + "GapAverage", Float.class).invoke(analysis, avgGap);
            // 设置率类差距字段（如果存在）
            try {
                analysis.getClass().getMethod("set" + capPrefix + "ExcellentRateGap", Float.class).invoke(analysis, excellentRateGap);
            } catch (NoSuchMethodException ignore) {}
            try {
                analysis.getClass().getMethod("set" + capPrefix + "FailRateGap", Float.class).invoke(analysis, failRateGap);
            } catch (NoSuchMethodException ignore) {}

            // 记录该课程包含的队次数量（如果两个队都有数据则为2，否则为非零队数）
            int teamCount = 0;
            if (scoresA != null && !scoresA.isEmpty()) teamCount++;
            if (scoresB != null && !scoresB.isEmpty()) teamCount++;
            try {
                analysis.getClass().getMethod("setTeamCount", Integer.class).invoke(analysis, teamCount);
            } catch (NoSuchMethodException ignore) {
                // 如果实体上没有 setTeamCount，则忽略（向前兼容）
            }
        } catch (NoSuchMethodException nsme) {
            logger.warn("Gap analysis setters not present for prefix={}", prefix);
        } catch (Exception e) {
            logger.error("Failed to compute/set team gap for prefix={}", prefix, e);
        }
    }

    @Override
    public void statisticsByTrainingLevel(String xueQe) {
        List<String> peiYangCengCiList = scoreRepository.findDistinctPeiYangCengCiByXueQe(xueQe);
    logger.info("statisticsByTrainingLevel: found {} 培养层次 for xueQe={}", peiYangCengCiList.size(), xueQe);
        
        for (String peiYangCengCi : peiYangCengCiList) {
            List<Score> scores = scoreRepository.findByXueQeAndPeiYangCengCi(xueQe, peiYangCengCi);
            
            TrainingLevelStatistics statistics = new TrainingLevelStatistics();
            statistics.setXueQe(xueQe);
            statistics.setPeiYangCengCi(peiYangCengCi);
            statistics.setTotalCount(scores.size());
            
            // 计算形成性成绩统计
            calculateStatistics(scores, statistics, GradeCalculator.XCX_SCORE_GETTER, "xcx");
            
            // 计算终结性成绩统计
            calculateStatistics(scores, statistics, GradeCalculator.ZJX_SCORE_GETTER, "zjx");
            
            // 计算总评成绩统计
            calculateStatistics(scores, statistics, GradeCalculator.ZP_SCORE_GETTER, "zp");
            
            trainingLevelStatisticsRepository.save(statistics);
            logger.debug("Saved TrainingLevelStatistics peiYangCengCi={} totalCount={}", peiYangCengCi, statistics.getTotalCount());
        }
    }

    @Override
    public void statisticsByTrainingLevelAndMajor(String xueQe) {
        List<String> peiYangCengCiList = scoreRepository.findDistinctPeiYangCengCiByXueQe(xueQe);
    logger.info("statisticsByTrainingLevelAndMajor: found {} 培养层次 for xueQe={}", peiYangCengCiList.size(), xueQe);
        
        for (String peiYangCengCi : peiYangCengCiList) {
            List<String> zhuanYeList = scoreRepository.findDistinctZhuanYeByXueQeAndPeiYangCengCi(xueQe, peiYangCengCi);
            
            for (String zhuanYe : zhuanYeList) {
                List<Score> scores = scoreRepository.findByXueQeAndPeiYangCengCiAndZhuanYe(xueQe, peiYangCengCi, zhuanYe);
                
                TrainingLevelMajorStatistics statistics = new TrainingLevelMajorStatistics();
                statistics.setXueQe(xueQe);
                statistics.setPeiYangCengCi(peiYangCengCi);
                statistics.setZhuanYe(zhuanYe);
                statistics.setTotalCount(scores.size());
                
                // 计算形成性成绩统计
                calculateStatistics(scores, statistics, GradeCalculator.XCX_SCORE_GETTER, "xcx");
                
                // 计算终结性成绩统计
                calculateStatistics(scores, statistics, GradeCalculator.ZJX_SCORE_GETTER, "zjx");
                
                // 计算总评成绩统计
                calculateStatistics(scores, statistics, GradeCalculator.ZP_SCORE_GETTER, "zp");
                
                trainingLevelMajorStatisticsRepository.save(statistics);
                logger.debug("Saved TrainingLevelMajorStatistics peiYangCengCi={} zhuanYe={} totalCount={}", peiYangCengCi, zhuanYe, statistics.getTotalCount());
            }
        }
    }

    @Override
    public void statisticsByTrainingLevelAndMajorAndTeam(String xueQe) {
        List<String> peiYangCengCiList = scoreRepository.findDistinctPeiYangCengCiByXueQe(xueQe);
    logger.info("statisticsByTrainingLevelAndMajorAndTeam: found {} 培养层次 for xueQe={}", peiYangCengCiList.size(), xueQe);
        
        for (String peiYangCengCi : peiYangCengCiList) {
            List<String> zhuanYeList = scoreRepository.findDistinctZhuanYeByXueQeAndPeiYangCengCi(xueQe, peiYangCengCi);
            
            for (String zhuanYe : zhuanYeList) {
                List<String> duiBieList = scoreRepository.findDistinctDuiBieByXueQeAndPeiYangCengCiAndZhuanYe(xueQe, peiYangCengCi, zhuanYe);
                
                for (String duiBie : duiBieList) {
                    List<Score> scores = scoreRepository.findByXueQeAndPeiYangCengCiAndZhuanYeAndDuiBie(xueQe, peiYangCengCi, zhuanYe, duiBie);
                    
                    TrainingLevelMajorTeamStatistics statistics = new TrainingLevelMajorTeamStatistics();
                    statistics.setXueQe(xueQe);
                    statistics.setPeiYangCengCi(peiYangCengCi);
                    statistics.setZhuanYe(zhuanYe);
                    statistics.setDuiBie(duiBie);
                    statistics.setTotalCount(scores.size());
                    
                    // 计算形成性成绩统计
                    calculateStatistics(scores, statistics, GradeCalculator.XCX_SCORE_GETTER, "xcx");
                    
                    // 计算终结性成绩统计
                    calculateStatistics(scores, statistics, GradeCalculator.ZJX_SCORE_GETTER, "zjx");
                    
                    // 计算总评成绩统计
                    calculateStatistics(scores, statistics, GradeCalculator.ZP_SCORE_GETTER, "zp");
                    
                    trainingLevelMajorTeamStatisticsRepository.save(statistics);
                    logger.debug("Saved TrainingLevelMajorTeamStatistics peiYangCengCi={} zhuanYe={} duiBie={} totalCount={}", peiYangCengCi, zhuanYe, duiBie, statistics.getTotalCount());
                }
            }
        }
    }

    @Override
    public void statisticsByTrainingLevelAndMajorAndTeamAndCourse(String xueQe) {
        List<String> peiYangCengCiList = scoreRepository.findDistinctPeiYangCengCiByXueQe(xueQe);
    logger.info("statisticsByTrainingLevelAndMajorAndTeamAndCourse: found {} 培养层次 for xueQe={}", peiYangCengCiList.size(), xueQe);
        
        for (String peiYangCengCi : peiYangCengCiList) {
            List<String> zhuanYeList = scoreRepository.findDistinctZhuanYeByXueQeAndPeiYangCengCi(xueQe, peiYangCengCi);
            
            for (String zhuanYe : zhuanYeList) {
                List<String> duiBieList = scoreRepository.findDistinctDuiBieByXueQeAndPeiYangCengCiAndZhuanYe(xueQe, peiYangCengCi, zhuanYe);
                
                for (String duiBie : duiBieList) {
                    List<Score> allScores = scoreRepository.findByXueQeAndPeiYangCengCiAndZhuanYeAndDuiBie(xueQe, peiYangCengCi, zhuanYe, duiBie);
                    
                    // 按课程分组
                    Map<String, List<Score>> courseGroups = allScores.stream()
                            .collect(Collectors.groupingBy(Score::getCourseCode));
                    
                    for (Map.Entry<String, List<Score>> entry : courseGroups.entrySet()) {
                        List<Score> scores = entry.getValue();
                        if (!scores.isEmpty()) {
                            Score firstScore = scores.get(0);
                            
                            TrainingLevelMajorTeamCourseStatistics statistics = new TrainingLevelMajorTeamCourseStatistics();
                            statistics.setXueQe(xueQe);
                            statistics.setPeiYangCengCi(peiYangCengCi);
                            statistics.setZhuanYe(zhuanYe);
                            statistics.setDuiBie(duiBie);
                            statistics.setCourseCode(firstScore.getCourseCode());
                            statistics.setCourseName(firstScore.getCourseName());
                            statistics.setCourseType(firstScore.getCourseType());
                            statistics.setTotalCount(scores.size());
                            
                            // 计算形成性成绩统计
                            calculateStatistics(scores, statistics, GradeCalculator.XCX_SCORE_GETTER, "xcx");
                            
                            // 计算终结性成绩统计
                            calculateStatistics(scores, statistics, GradeCalculator.ZJX_SCORE_GETTER, "zjx");
                            
                            // 计算总评成绩统计
                            calculateStatistics(scores, statistics, GradeCalculator.ZP_SCORE_GETTER, "zp");
                            
                            trainingLevelMajorTeamCourseStatisticsRepository.save(statistics);
                            logger.debug("Saved TrainingLevelMajorTeamCourseStatistics courseCode={} totalCount={}", statistics.getCourseCode(), statistics.getTotalCount());
                        }
                    }
                }
            }
        }
    }

    @Override
    public void statisticsByCourse(String xueQe) {
        List<Object[]> courses = scoreRepository.findDistinctCoursesByXueQe(xueQe);
    logger.info("statisticsByCourse: found {} courses for xueQe={}", courses.size(), xueQe);
        
        for (Object[] course : courses) {
            String courseCode = (String) course[0];
            String courseName = (String) course[1];
            
            List<Score> scores = scoreRepository.findByXueQeAndCourseCode(xueQe, courseCode);
            
            if (!scores.isEmpty()) {
                Score firstScore = scores.get(0);
                
                CourseStatistics statistics = new CourseStatistics();
                statistics.setXueQe(xueQe);
                statistics.setCourseCode(courseCode);
                statistics.setCourseName(courseName);
                statistics.setCourseType(firstScore.getCourseType());
                statistics.setTotalCount(scores.size());
                
                // 计算形成性成绩统计
                calculateStatistics(scores, statistics, GradeCalculator.XCX_SCORE_GETTER, "xcx");
                
                // 计算终结性成绩统计
                calculateStatistics(scores, statistics, GradeCalculator.ZJX_SCORE_GETTER, "zjx");
                
                // 计算总评成绩统计
                calculateStatistics(scores, statistics, GradeCalculator.ZP_SCORE_GETTER, "zp");
                
                courseStatisticsRepository.save(statistics);
                logger.debug("Saved CourseStatistics courseCode={} totalCount={}", courseCode, statistics.getTotalCount());
            }
        }
    }

    @Override
    public void analyzeCourseGap(String xueQe) {
        // 为每门课程计算不同队别间的平均分差距，并保留每项指标（形成性/终结性/总评）中最大平均差的队别对
        List<Object[]> courses = scoreRepository.findDistinctCoursesByXueQe(xueQe);
        List<String> courseCodes = courses.stream()
                .map(course -> (String) course[0])
                .collect(Collectors.toList());

        for (String courseCode : courseCodes) {
            List<Score> courseScores = scoreRepository.findByXueQeAndCourseCode(xueQe, courseCode);
            if (courseScores.isEmpty()) continue;

            // 按队别分组
            Map<String, List<Score>> teamGroups = courseScores.stream()
                    .collect(Collectors.groupingBy(s -> s.getDuiBie() == null ? "" : s.getDuiBie()));

            List<String> teams = new ArrayList<>(teamGroups.keySet());
            if (teams.size() < 2) continue; // 少于两队则无法比较

            // 记录当前最大平均差及对应队别
            float bestXcxGap = -1f; String bestXcxA = null, bestXcxB = null;
            float bestZjxGap = -1f; String bestZjxA = null, bestZjxB = null;
            float bestZpGap = -1f;  String bestZpA = null,  bestZpB = null;

            // 两两比较，计算平均差（基于各队的平均分）用于评判最大平均差
            for (int i = 0; i < teams.size(); i++) {
                for (int j = i + 1; j < teams.size(); j++) {
                    String teamA = teams.get(i);
                    String teamB = teams.get(j);
                    List<Score> scoresA = teamGroups.get(teamA);
                    List<Score> scoresB = teamGroups.get(teamB);
                    if (scoresA == null || scoresB == null) continue;

                    Float avgA_xcx = GradeCalculator.calculateAverage(scoresA, GradeCalculator.XCX_SCORE_GETTER);
                    Float avgB_xcx = GradeCalculator.calculateAverage(scoresB, GradeCalculator.XCX_SCORE_GETTER);
                    if (avgA_xcx != null && avgB_xcx != null) {
                        float gap = Math.abs(avgA_xcx - avgB_xcx);
                        if (gap > bestXcxGap) {
                            bestXcxGap = gap; bestXcxA = teamA; bestXcxB = teamB;
                        }
                    }

                    Float avgA_zjx = GradeCalculator.calculateAverage(scoresA, GradeCalculator.ZJX_SCORE_GETTER);
                    Float avgB_zjx = GradeCalculator.calculateAverage(scoresB, GradeCalculator.ZJX_SCORE_GETTER);
                    if (avgA_zjx != null && avgB_zjx != null) {
                        float gap = Math.abs(avgA_zjx - avgB_zjx);
                        if (gap > bestZjxGap) {
                            bestZjxGap = gap; bestZjxA = teamA; bestZjxB = teamB;
                        }
                    }

                    Float avgA_zp = GradeCalculator.calculateAverage(scoresA, GradeCalculator.ZP_SCORE_GETTER);
                    Float avgB_zp = GradeCalculator.calculateAverage(scoresB, GradeCalculator.ZP_SCORE_GETTER);
                    if (avgA_zp != null && avgB_zp != null) {
                        float gap = Math.abs(avgA_zp - avgB_zp);
                        if (gap > bestZpGap) {
                            bestZpGap = gap; bestZpA = teamA; bestZpB = teamB;
                        }
                    }
                }
            }

            // 若至少有一项指标有比较结果，则保存一条记录（只记录各项最大差值与队次数量，不记录具体队名）
            if (bestXcxGap >= 0 || bestZjxGap >= 0 || bestZpGap >= 0) {
                CourseGapAnalysis analysis = new CourseGapAnalysis();
                analysis.setXueQe(xueQe);
                // 使用单一 courseCode / courseName 字段
                analysis.setCourseCode(courseCode);
                analysis.setCourseName(courseScores.get(0).getCourseName());

                // 记录该课程包含的队次数量
                analysis.setTeamCount(teams.size());

                if (bestXcxGap >= 0) {
                    analysis.setXcxGapAverage(bestXcxGap);
                    // legacy fields for team names left untouched
                }
                // 计算并设置形成性优秀率/不及格率差距
                if (bestXcxA != null && bestXcxB != null) {
                    List<Score> scoresA = teamGroups.get(bestXcxA);
                    List<Score> scoresB = teamGroups.get(bestXcxB);
                    Map<String, Integer> countsA = GradeCalculator.countGradeLevels(scoresA, GradeCalculator.XCX_SCORE_GETTER);
                    Map<String, Integer> countsB = GradeCalculator.countGradeLevels(scoresB, GradeCalculator.XCX_SCORE_GETTER);
                    int validA = scoresA == null ? 0 : (int) scoresA.stream().filter(s -> GradeCalculator.XCX_SCORE_GETTER.getScore(s) != null).count();
                    int validB = scoresB == null ? 0 : (int) scoresB.stream().filter(s -> GradeCalculator.XCX_SCORE_GETTER.getScore(s) != null).count();
                    try {
                        Float exA = validA > 0 ? new java.math.BigDecimal(countsA.getOrDefault("excellent", 0)).divide(new java.math.BigDecimal(validA), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float exB = validB > 0 ? new java.math.BigDecimal(countsB.getOrDefault("excellent", 0)).divide(new java.math.BigDecimal(validB), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float fA = validA > 0 ? new java.math.BigDecimal(countsA.getOrDefault("fail", 0)).divide(new java.math.BigDecimal(validA), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float fB = validB > 0 ? new java.math.BigDecimal(countsB.getOrDefault("fail", 0)).divide(new java.math.BigDecimal(validB), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        if (exA != null && exB != null) analysis.setXcxExcellentRateGap(Math.abs(exA - exB));
                        if (fA != null && fB != null) analysis.setXcxFailRateGap(Math.abs(fA - fB));
                    } catch (Exception ignore) {}
                }
                if (bestZjxGap >= 0) {
                    analysis.setZjxGapAverage(bestZjxGap);
                    // legacy team fields left untouched
                }
                // 计算并设置终结性优秀率/不及格率差距
                if (bestZjxA != null && bestZjxB != null) {
                    List<Score> scoresA = teamGroups.get(bestZjxA);
                    List<Score> scoresB = teamGroups.get(bestZjxB);
                    Map<String, Integer> countsA = GradeCalculator.countGradeLevels(scoresA, GradeCalculator.ZJX_SCORE_GETTER);
                    Map<String, Integer> countsB = GradeCalculator.countGradeLevels(scoresB, GradeCalculator.ZJX_SCORE_GETTER);
                    int validA = scoresA == null ? 0 : (int) scoresA.stream().filter(s -> GradeCalculator.ZJX_SCORE_GETTER.getScore(s) != null).count();
                    int validB = scoresB == null ? 0 : (int) scoresB.stream().filter(s -> GradeCalculator.ZJX_SCORE_GETTER.getScore(s) != null).count();
                    try {
                        Float exA = validA > 0 ? new java.math.BigDecimal(countsA.getOrDefault("excellent", 0)).divide(new java.math.BigDecimal(validA), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float exB = validB > 0 ? new java.math.BigDecimal(countsB.getOrDefault("excellent", 0)).divide(new java.math.BigDecimal(validB), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float fA = validA > 0 ? new java.math.BigDecimal(countsA.getOrDefault("fail", 0)).divide(new java.math.BigDecimal(validA), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float fB = validB > 0 ? new java.math.BigDecimal(countsB.getOrDefault("fail", 0)).divide(new java.math.BigDecimal(validB), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        if (exA != null && exB != null) analysis.setZjxExcellentRateGap(Math.abs(exA - exB));
                        if (fA != null && fB != null) analysis.setZjxFailRateGap(Math.abs(fA - fB));
                    } catch (Exception ignore) {}
                }
                if (bestZpGap >= 0) {
                    analysis.setZpGapAverage(bestZpGap);
                    // legacy team fields left untouched
                }
                // 计算并设置总评优秀率/不及格率差距
                if (bestZpA != null && bestZpB != null) {
                    List<Score> scoresA = teamGroups.get(bestZpA);
                    List<Score> scoresB = teamGroups.get(bestZpB);
                    Map<String, Integer> countsA = GradeCalculator.countGradeLevels(scoresA, GradeCalculator.ZP_SCORE_GETTER);
                    Map<String, Integer> countsB = GradeCalculator.countGradeLevels(scoresB, GradeCalculator.ZP_SCORE_GETTER);
                    int validA = scoresA == null ? 0 : (int) scoresA.stream().filter(s -> GradeCalculator.ZP_SCORE_GETTER.getScore(s) != null).count();
                    int validB = scoresB == null ? 0 : (int) scoresB.stream().filter(s -> GradeCalculator.ZP_SCORE_GETTER.getScore(s) != null).count();
                    try {
                        Float exA = validA > 0 ? new java.math.BigDecimal(countsA.getOrDefault("excellent", 0)).divide(new java.math.BigDecimal(validA), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float exB = validB > 0 ? new java.math.BigDecimal(countsB.getOrDefault("excellent", 0)).divide(new java.math.BigDecimal(validB), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float fA = validA > 0 ? new java.math.BigDecimal(countsA.getOrDefault("fail", 0)).divide(new java.math.BigDecimal(validA), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
                        Float fB = validB > 0 ? new java.math.BigDecimal(countsB.getOrDefault("fail", 0)).divide(new java.math.BigDecimal(validB), 5, java.math.RoundingMode.HALF_UP).setScale(3, java.math.RoundingMode.HALF_UP).floatValue() : null;
            if (exA != null && exB != null) analysis.setZpExcellentRateGap(Math.abs(exA - exB));
            if (fA != null && fB != null) analysis.setZpFailRateGap(Math.abs(fA - fB));
                    } catch (Exception ignore) {}
                }
        // 保存并记录（不再输出具体队别名称）
        courseGapAnalysisRepository.save(analysis);
        logger.debug("Saved CourseGapAnalysis course={} teamCount={} xcxGap={} zjxGap={} zpGap= {}", courseCode, analysis.getTeamCount(), analysis.getXcxGapAverage(), analysis.getZjxGapAverage(), analysis.getZpGapAverage());
            }
        }
    }

    // 课程相关性分析已移除

    /**
    * 原先用于排除考查课的逻辑已删除，根据当前要求保留 examType 字段但不做排除。
    */

    @Override
    public void clearAllStatistics() {
    logger.info("Clearing all statistics tables...");
    trainingLevelStatisticsRepository.deleteAll();
    trainingLevelMajorStatisticsRepository.deleteAll();
    trainingLevelMajorTeamStatisticsRepository.deleteAll();
    trainingLevelMajorTeamCourseStatisticsRepository.deleteAll();
    courseStatisticsRepository.deleteAll();
    courseGapAnalysisRepository.deleteAll();
    logger.info("All statistics tables cleared");
    }

    /**
     * 计算统计数据并设置到统计对象中
     * @param scores 成绩列表
     * @param statistics 统计对象
     * @param scoreGetter 成绩获取器
     * @param prefix 前缀（xcx、zjx、zp）
     */
    private void calculateStatistics(List<Score> scores, Object statistics, 
                                   GradeCalculator.ScoreGetter scoreGetter, String prefix) {
    logger.debug("calculateStatistics prefix={} scoresSize={}", prefix, scores == null ? 0 : scores.size());
        Float average = GradeCalculator.calculateAverage(scores, scoreGetter);
    logger.debug("{} average={}", prefix, average);
        Float standardDeviation = GradeCalculator.calculateStandardDeviation(scores, scoreGetter);
    logger.debug("{} standardDeviation={}", prefix, standardDeviation);
        Map<String, Integer> gradeLevelCounts = GradeCalculator.countGradeLevels(scores, scoreGetter);
    logger.debug("{} gradeLevelCounts={}", prefix, gradeLevelCounts);

            try {
            // 使用反射设置属性值 — 首字母大写以匹配 Lombok/JavaBean 风格的 setter（例如 setXcxAverage）
            String capPrefix = prefix.substring(0, 1).toUpperCase() + prefix.substring(1);
            logger.debug("Using reflection with prefix={} capPrefix={}", prefix, capPrefix);
            // 平均值与标准差
            statistics.getClass().getMethod("set" + capPrefix + "Average", Float.class).invoke(statistics, average);
            statistics.getClass().getMethod("set" + capPrefix + "StandardDeviation", Float.class).invoke(statistics, standardDeviation);
            // 中位数
            Float median = GradeCalculator.calculateMedian(scores, scoreGetter);
            try {
                statistics.getClass().getMethod("set" + capPrefix + "Median", Float.class).invoke(statistics, median);
            } catch (NoSuchMethodException ignore) {
                // 如果某个统计对象没有 median 字段，忽略
            }
            statistics.getClass().getMethod("set" + capPrefix + "ExcellentCount", Integer.class).invoke(statistics, gradeLevelCounts.get("excellent"));
            statistics.getClass().getMethod("set" + capPrefix + "GoodCount", Integer.class).invoke(statistics, gradeLevelCounts.get("good"));
            // 中等已并入及格，不再设置 MediumCount
            statistics.getClass().getMethod("set" + capPrefix + "PassCount", Integer.class).invoke(statistics, gradeLevelCounts.get("pass"));
            statistics.getClass().getMethod("set" + capPrefix + "FailCount", Integer.class).invoke(statistics, gradeLevelCounts.get("fail"));
        // 计算并设置比率字段（保留3位小数），以有效记录数为分母
        int validCount = (scores == null) ? 0 : (int) scores.stream().filter(s -> scoreGetter.getScore(s) != null).count();
        try {
        if (validCount > 0) {
            Float excellentRate = new java.math.BigDecimal(gradeLevelCounts.getOrDefault("excellent", 0))
                .divide(new java.math.BigDecimal(validCount), 5, java.math.RoundingMode.HALF_UP)
                .setScale(3, java.math.RoundingMode.HALF_UP).floatValue();
            Float goodRate = new java.math.BigDecimal(gradeLevelCounts.getOrDefault("good", 0))
                .divide(new java.math.BigDecimal(validCount), 5, java.math.RoundingMode.HALF_UP)
                .setScale(3, java.math.RoundingMode.HALF_UP).floatValue();
            Float passRate = new java.math.BigDecimal(gradeLevelCounts.getOrDefault("pass", 0))
                .divide(new java.math.BigDecimal(validCount), 5, java.math.RoundingMode.HALF_UP)
                .setScale(3, java.math.RoundingMode.HALF_UP).floatValue();
            Float failRate = new java.math.BigDecimal(gradeLevelCounts.getOrDefault("fail", 0))
                .divide(new java.math.BigDecimal(validCount), 5, java.math.RoundingMode.HALF_UP)
                .setScale(3, java.math.RoundingMode.HALF_UP).floatValue();

            // 反射设置 rate 字段（如果存在）
            try { statistics.getClass().getMethod("set" + capPrefix + "ExcellentRate", Float.class).invoke(statistics, excellentRate); } catch (NoSuchMethodException ignore){}
            try { statistics.getClass().getMethod("set" + capPrefix + "GoodRate", Float.class).invoke(statistics, goodRate); } catch (NoSuchMethodException ignore){}
            try { statistics.getClass().getMethod("set" + capPrefix + "PassRate", Float.class).invoke(statistics, passRate); } catch (NoSuchMethodException ignore){}
            try { statistics.getClass().getMethod("set" + capPrefix + "FailRate", Float.class).invoke(statistics, failRate); } catch (NoSuchMethodException ignore){}
        }
        } catch (Exception e) {
        logger.warn("Failed to compute/set rate fields for prefix={}", prefix, e);
        }
        } catch (Exception e) {
            logger.error("Failed to set statistics via reflection for prefix={}; statisticsClass={}", prefix, statistics == null ? "null" : statistics.getClass().getName(), e);
            throw new RuntimeException("设置统计数据失败", e);
        }
    }

    /**
     * 计算差距分析并设置到分析对象中
     * @param scores1 第一组成绩
     * @param scores2 第二组成绩
     * @param analysis 分析对象
     * @param scoreGetter 成绩获取器
     * @param prefix 前缀（xcx、zjx、zp）
     */
    private void calculateGapAnalysis(List<Score> scores1, List<Score> scores2, CourseGapAnalysis analysis,
                                     GradeCalculator.ScoreGetter scoreGetter, String prefix) {
        Map<String, Float> scoreMap1 = createScoreMap(scores1, scoreGetter);
        Map<String, Float> scoreMap2 = createScoreMap(scores2, scoreGetter);
        
        List<Float> gaps = new ArrayList<>();
        for (Map.Entry<String, Float> entry : scoreMap1.entrySet()) {
            Float score2 = scoreMap2.get(entry.getKey());
            if (score2 != null) {
                gaps.add(Math.abs(entry.getValue() - score2));
            }
        }
        
        if (!gaps.isEmpty()) {
            float averageGap = (float) gaps.stream().mapToDouble(Float::floatValue).average().orElse(0);
            float maxGap = gaps.stream().max(Float::compare).orElse(0f);
            float minGap = gaps.stream().min(Float::compare).orElse(0f);
            
            // 计算标准差差距
            Float stdDev1 = GradeCalculator.calculateStandardDeviation(scores1, scoreGetter);
            Float stdDev2 = GradeCalculator.calculateStandardDeviation(scores2, scoreGetter);
            Float stdDevGap = null;
            if (stdDev1 != null && stdDev2 != null) {
                stdDevGap = Math.abs(stdDev1 - stdDev2);
            }
            
            try {
                String capPrefix = prefix.substring(0, 1).toUpperCase() + prefix.substring(1);
                analysis.getClass().getMethod("set" + capPrefix + "GapAverage", Float.class).invoke(analysis, averageGap);
                analysis.getClass().getMethod("set" + capPrefix + "MaxGap", Float.class).invoke(analysis, maxGap);
                analysis.getClass().getMethod("set" + capPrefix + "MinGap", Float.class).invoke(analysis, minGap);
                analysis.getClass().getMethod("set" + capPrefix + "StandardDeviationGap", Float.class).invoke(analysis, stdDevGap);
            } catch (Exception e) {
                logger.error("Failed to set gap analysis fields for prefix={}; analysisClass={}", prefix, analysis == null ? "null" : analysis.getClass().getName(), e);
                throw new RuntimeException("设置差距分析数据失败", e);
            }
        }
    }

    /**
     * 创建成绩映射表
     * @param scores 成绩列表
     * @param scoreGetter 成绩获取器
     * @return 学号到成绩的映射表
     */
    private Map<String, Float> createScoreMap(List<Score> scores, GradeCalculator.ScoreGetter scoreGetter) {
        Map<String, Float> scoreMap = new HashMap<>();
        for (Score score : scores) {
            Float value = scoreGetter.getScore(score);
            if (value != null && score.getXh() != null) {
                scoreMap.put(score.getXh(), value);
            }
        }
        return scoreMap;
    }
}